﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Atlantyda
{
    public class AgentMap
    {
        private int agent_orientation = 0;
        private int agent_x = 0;
        private int agent_y = 0;
        private int size = 0;
        private AgentMapField actual_field_archive = null;
        private Dictionary<String, AgentMapField> fields = new Dictionary<String, AgentMapField>();

        public AgentMap() { }

        public AgentMap(int o)
        {
            agent_orientation = o;
        }

        public bool AddField(int x, int y, int h, int e = 0, bool o = false)
        {
            if (fields.ContainsKey(GeneratrKey(x, y)))
                return false;
            else
            {
                AgentMapField field = new AgentMapField(x, y, h, e, o);
                fields.Add(GeneratrKey(x, y), field);
                return true;
            }
        }

        public bool AddLookField(int x, int y, int h, int e = 0, bool o = false)
        {
            if (AgentMap.TransformXY(x, y, agent_orientation, agent_x, agent_y, out x, out y))
                return AddField(x, y, h, e, o);
            else
                return false;
        }

        public void setOrientation(byte direction)
        {
            switch (direction)
            {
                case 0:
                    if (agent_orientation > 0)
                        agent_orientation--;
                    else
                        agent_orientation = 3;
                    break;
                case 1:
                    if (agent_orientation < 3)
                        agent_orientation++;
                    else
                        agent_orientation = 0;
                    break;
            }
        }

        public void StepForward()
        {
            switch (agent_orientation)
            {
                case 0:
                    agent_y++;
                    break;
                case 1:
                    agent_x++;
                    break;
                case 2:
                    agent_y--;
                    break;
                case 3:
                    agent_x--;
                    break;
            }
            actual_field_archive = new AgentMapField(GetActualField());
            GetActualField().LastOrientation = agent_orientation;
            GetActualField().LastRotate = new List<String>();
        }

        public void GetEnergyFromField(int energy)
        {
            AgentMapField field;
            if (fields.TryGetValue(GeneratrKey(agent_x, agent_y), out field) && field.Energy != -1)
            {
                field.Energy -= energy;
            }
        }

        private String GeneratrKey(int x, int y)
        {
            return x + "_" + y;
        }

        public static bool TransformXY(int x, int y, int orientate, int agent_x, int agent_y, out int tx, out int ty)
        {
            switch (orientate)
            {
                case 0:
                    tx = x;
                    ty = y;
                    break;
                case 1:
                    tx = y;
                    ty = x * (-1);
                    break;
                case 2:
                    tx = x * (-1);
                    ty = y * (-1);
                    break;
                case 3:
                    tx = y * (-1);
                    ty = x;
                    break;
                default:
                    tx = ty = 0;
                    return false;
            }
            tx += agent_x;
            ty += agent_y;
            return true;
        }

        public AgentMapField GetActualField()
        {
            AgentMapField field;
            if (fields.TryGetValue(GeneratrKey(agent_x, agent_y), out field))
                return field;
            else
                return null;
        }

        public int AgentOrientation
        {
            get { return agent_orientation; }
        }

        public Dictionary<String, AgentMapField> Fields
        {
            get { return fields; }
        }

        public AgentMapField ActualFieldArchive
        {
            get { return actual_field_archive; }
        }

        public int AgentX
        {
            get { return agent_x; }
        }

        public int AgentY
        {
            get { return agent_y; }
        }

        public int Size
        {
            get { return size; }
            set { size = value; }
        }

        public bool FindEnergy(out int x, out int y)
        {
            foreach (KeyValuePair<String, AgentMapField> field in fields)
            {
                if (field.Value.Energy > 0)
                {
                    x = field.Value.CoordianteX;
                    y = field.Value.CoordianteY;
                    return true;
                }
            }
            x = y = 0;
            return false;
        }

        public bool FindObstacle(out int x, out int y)
        {
            foreach (KeyValuePair<String, AgentMapField> field in fields)
            {
                if (field.Value.Obstacle)
                {
                    x = field.Value.CoordianteX;
                    y = field.Value.CoordianteY;
                    return true;
                }
            }
            x = y = 0;
            return false;
        }
    }
}
